package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.tbit.Version;
import com.tbit.uqbike.constant.OperaPswConstant;
import com.tbit.uqbike.enums.DispatchApplyHandleType;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.Account;
import com.tbit.uqbike.object.pojo.DispatchApplyLog;
import com.tbit.uqbike.object.pojo.dto.DispatchApplyDealApplyDTO;
import com.tbit.uqbike.object.pojo.vo.DispatchApplyAggregationCSV;
import com.tbit.uqbike.object.pojo.vo.DispatchApplyFlatCSV;
import com.tbit.uqbike.object.pojo.vo.DispatchApplyVO;
import com.tbit.common.entity.view.PageResult;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.service.business.DispatchApplyLogService;
import com.tbit.uqbike.webmanager.dao.core.AccountDao;
import com.tbit.uqbike.webmanager.dao.log.DispatchApplyLogDao;
import com.tbit.uqbike.webmanager.util.csv.CsvExportUtils;
import com.tbit.uqbike.webmanager.util.csv.entity.ExportHandler;
import com.tbit.uqbike.webmanager.util.excel.ExcelUtil;
import com.tbit.utils.DateTimeUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.function.IntSupplier;
import java.util.stream.Collectors;

/**
 * @author yee_
 * @version 1.0
 * @date 2023/2/13 19:24
 */
@Service
public class DispatchApplyLogImpl extends ServiceImpl<DispatchApplyLogDao, DispatchApplyLog> implements DispatchApplyLogService {

    private static final Log logger = LogFactory.getLog(DispatchApplyLogImpl.class);

    @Resource
    private AccountDao accountDao;
    @Autowired
    private DispatchApplyLogDao dispatchApplyLogDao;
    @Autowired
    private CsvExportUtils csvExportUtils;

    @Override
    public Result<PageResult<DispatchApplyVO>> listPage(Integer accountId, Integer applyUserId, Integer state, DispatchApplyHandleType handleType,
                                                        Integer page, Integer size, Long startTime, Long endTime) {
        Map<String, Object> queryMap = new HashMap<>(16);
        LambdaQueryWrapper<DispatchApplyLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DispatchApplyLog::getAccountId, accountId);
        if (Objects.nonNull(applyUserId)) {
            queryWrapper.eq(DispatchApplyLog::getApplyUserId, applyUserId);
        }
        if (Objects.nonNull(state)) {
            queryWrapper.eq(DispatchApplyLog::getState, state);
        }
        if (Objects.nonNull(startTime)) {
            queryMap.put("startTime", DateTimeUtil.DateTimeToString(new Date(startTime)));
            queryWrapper.ge(DispatchApplyLog::getApplyTime, DateTimeUtil.DateTimeToString(new Date(startTime)));
        }
        if (Objects.nonNull(endTime)) {
            queryWrapper.le(DispatchApplyLog::getApplyTime, DateTimeUtil.DateTimeToString(new Date(endTime)));
            queryMap.put("endTime", DateTimeUtil.DateTimeToString(new Date(endTime)));
        }
        if (Objects.nonNull(handleType)) {
            queryMap.put("handleType", handleType);
            queryWrapper.eq(DispatchApplyLog::getHandleType,handleType.getCode());
        }
        Long dataCount = dispatchApplyLogDao.selectCount(queryWrapper);
        if (dataCount <= 0) {
            return Result.success(
                    new PageResult<>(page, size, 0L, 0, Collections.emptyList())
            );
        }
        queryMap.put("accountId", accountId);
        queryMap.put("applyUserId", applyUserId);
        queryMap.put("state", state);
        queryMap.put("page", (page - 1) * size);
        queryMap.put("size", size);
        List<DispatchApplyVO> resultList = dispatchApplyLogDao.listPage(queryMap);
        Map<Integer, String> accountNameMap = accountDao.getByAccountIds(resultList.stream()
                                                                                   .map(DispatchApplyVO::getDispatchApplyLog)
                                                                                   .map(DispatchApplyLog::getAccountId).collect(Collectors.toList()))
                                                        .stream().collect(Collectors.toMap(Account::getAccountId, Account::getName));
        resultList.forEach(x -> x.setAccountName(accountNameMap.getOrDefault(x.getDispatchApplyLog().getAccountId(), "-")));
        return Result.success(
                new PageResult<>(page, size, dataCount,
                        dataCount % size == 0 ? (int) (dataCount / size) : (int) (dataCount / size) + 1,
                        resultList)
        );
    }

    @Override
    public String exportCsv(Integer accountId, Integer applyUserId, Integer state, DispatchApplyHandleType handleType, Long startTime, Long endTime) {
        Map<String, Object> queryMap = new HashMap<>(16);
        LambdaQueryWrapper<DispatchApplyLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DispatchApplyLog::getAccountId, accountId);
        if (Objects.nonNull(applyUserId)) {
            queryWrapper.eq(DispatchApplyLog::getApplyId, applyUserId);
        }
        if (Objects.nonNull(state)) {
            queryWrapper.eq(DispatchApplyLog::getState, state);
        }
        if (Objects.nonNull(startTime)) {
            queryMap.put("startTime", DateTimeUtil.DateTimeToString(new Date(startTime)));
            queryWrapper.ge(DispatchApplyLog::getApplyTime, DateTimeUtil.DateTimeToString(new Date(startTime)));
        }
        if (Objects.nonNull(endTime)) {
            queryWrapper.le(DispatchApplyLog::getApplyTime, DateTimeUtil.DateTimeToString(new Date(endTime)));
            queryMap.put("endTime", DateTimeUtil.DateTimeToString(new Date(endTime)));
        }
        if (Objects.nonNull(handleType)) {
            queryMap.put("handleType", handleType);
            queryWrapper.eq(DispatchApplyLog::getHandleType,handleType.getCode());
        }


        queryMap.put("accountId", accountId);
        queryMap.put("applyUserId", applyUserId);
        queryMap.put("state", state);
        IntSupplier countFn = () -> (int) PageHelper.startPage(1, 1).doSelectPageInfo(() -> dispatchApplyLogDao.queryAll(queryMap)).getTotal();

        List<DispatchApplyVO> resultList = dispatchApplyLogDao.queryAll(queryMap);

        ExportHandler exportHandler;
        if (CollectionUtil.isNotEmpty(resultList)) {
            Map<Integer, String> accountNameMap = accountDao.getByAccountIds(resultList.stream()
                                                                                       .map(DispatchApplyVO::getDispatchApplyLog)
                                                                                       .map(DispatchApplyLog::getAccountId).collect(Collectors.toList()))
                                                            .stream().collect(Collectors.toMap(Account::getAccountId, Account::getName));

            exportHandler = baseEntity -> {
                for (DispatchApplyVO vo : resultList) {
                    vo.setAccountName(accountNameMap.getOrDefault(vo.getDispatchApplyLog().getAccountId(), "-"));
                }
                return  resultList.stream()
                                  .map(DispatchApplyVO::aggregation)
                                  .collect(Collectors.toList());
            };

        }else {
            exportHandler = baseEntity -> Collections.emptyList();
        }

        File tempFile = csvExportUtils.getTempFile();
        File file = csvExportUtils.exportBigCsvUseDynamicDate(exportHandler, DispatchApplyAggregationCSV.class, countFn, new Date(startTime), new Date(endTime), tempFile, "调度申请");
        return csvExportUtils.uploadZip(tempFile, UUID.randomUUID().toString().replace("-", ""), file);

    }

    @Override
    public void dealWithApply(DispatchApplyDealApplyDTO reviewDTO) {
        Integer applyId = reviewDTO.getApplyId();
        DispatchApplyLog applyLog = dispatchApplyLogDao.selectById(applyId);
        if (Objects.isNull(applyLog)) {
            throw new BaseException("调度申请记录不存在");
        }
        if (applyLog.getState() != 0) {
            throw new BaseException("调度申请已被审批,请勿重复处理");
        }
        Integer state = reviewDTO.getHandleResult() ? 1 : 2;
        String url = String.format("/dispatchApplyLog/handle.do?applyId=%d&state=%d&remark=%s&accountUserIdManager=%d",
                applyId, state, StringUtils.defaultIfBlank(reviewDTO.getHandleRemark(), ""), reviewDTO.getStockUserId());
        String res = HttpUtil.createGet(OperaPswConstant.ACCOUNT_OPERA_MAIN_URL + url)
                             .header("U-APP-VERSION", Version.getVersion())
                             .execute()
                             .body();
        logger.info("运维调度审核调用url:" + url + ",运维端返回:" + res);
    }

    @Override
    public Result<Object> export(Integer accountId, Integer applyUserId, Integer state, DispatchApplyHandleType type, Long startTime, Long endTime) {
        Map<String, Object> queryMap = new HashMap<>(16);
        LambdaQueryWrapper<DispatchApplyLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DispatchApplyLog::getAccountId, accountId);
        if (Objects.nonNull(applyUserId)) {
            queryWrapper.eq(DispatchApplyLog::getApplyId, applyUserId);
        }
        if (Objects.nonNull(state)) {
            queryWrapper.eq(DispatchApplyLog::getState, state);
        }
        if (Objects.nonNull(startTime)) {
            queryMap.put("startTime", DateTimeUtil.DateTimeToString(new Date(startTime)));
            queryWrapper.ge(DispatchApplyLog::getApplyTime, DateTimeUtil.DateTimeToString(new Date(startTime)));
        }
        if (Objects.nonNull(endTime)) {
            queryWrapper.le(DispatchApplyLog::getApplyTime, DateTimeUtil.DateTimeToString(new Date(endTime)));
            queryMap.put("endTime", DateTimeUtil.DateTimeToString(new Date(endTime)));
        }
        if (Objects.nonNull(type)) {
            queryMap.put("handleType", type);
            queryWrapper.eq(DispatchApplyLog::getHandleType,type.getCode());
        }

        queryMap.put("accountId", accountId);
        queryMap.put("applyUserId", applyUserId);
        queryMap.put("state", state);

        List<DispatchApplyVO> resultList = dispatchApplyLogDao.queryAll(queryMap);
        List<DispatchApplyAggregationCSV> excelList = new ArrayList<>();

        if (CollectionUtil.isNotEmpty(resultList)) {
            Map<Integer, String> accountNameMap = accountDao.getByAccountIds(resultList.stream()
                            .map(DispatchApplyVO::getDispatchApplyLog)
                            .map(DispatchApplyLog::getAccountId).collect(Collectors.toList()))
                    .stream().collect(Collectors.toMap(Account::getAccountId, Account::getName));
            for (DispatchApplyVO vo : resultList) {
                vo.setAccountName(accountNameMap.getOrDefault(vo.getDispatchApplyLog().getAccountId(), "-"));
                DispatchApplyAggregationCSV aggregation = vo.aggregation();
                excelList.add(aggregation);
            }
        }

        ExcelUtil<DispatchApplyAggregationCSV> excelUtil = new ExcelUtil<>(DispatchApplyAggregationCSV.class);
        String name = String.format("%s~%s_调度申请", DateUtil.formatDate(new Date(startTime)), DateUtil.formatDate(new Date(endTime)));
        return Result.success(excelUtil.exportExcel(excelList, name).getData());
    }
}
